#ifndef SC_CAR_DEF_MANAGER_H_INCLUDED
#define SC_CAR_DEF_MANAGER_H_INCLUDED

#include <map>
#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>
#include "../../../math/vector3f.h"

class ScWheelDef
{
public:
	ScWheelDef(const std::string id, const float radius, const float width, const float friction, const std::string& objPath) :
	m_id(id),
	m_radius(radius),
	m_width(width),
	m_friction(friction),
	m_objPath(objPath)
	{
	}
	const std::string& getId() const { return m_id; }
	float getRadius() const { return m_radius; }
	float getWidth() const { return m_width; }
	float getFriction() const { return m_friction; }
	const std::string& getObjPath() const { return m_objPath; }
private:
	std::string m_id;
	float m_radius;
	float m_width;
	float m_friction;
	std::string m_objPath;
};

class ScSuspensionDef
{
public:
	ScSuspensionDef(const std::string& id, const float stiffness, const float damping, const float compression, const float length, const float rollInfluence, const float maximumForce) :
	m_id(id),
	m_stiffness(stiffness),
	m_damping(damping),
	m_compression(compression),
	m_length(length),
	m_rollInfluence(rollInfluence),
	m_maximumForce(maximumForce)
	{
	}
	const std::string& getId() const { return m_id; }
	float getStiffness() const { return m_stiffness; }
	float getDamping() const { return m_damping; }
	float getCompression() const { return m_compression; }
	float getLength() const { return m_length; }
	float getRollInfluence() const { return m_rollInfluence; }
	float getMaximumForce() const { return m_maximumForce; }
private:
	std::string m_id;
	float m_stiffness;
	float m_damping;
	float m_compression;
	float m_length;
	float m_rollInfluence;
	float m_maximumForce;
};

class ScBrakesDef
{
public:
	ScBrakesDef(const std::string& id, const float force) :
	m_id(id),
	m_force(force)
	{
	}
	const std::string& getId() const { return m_id; }
	float getForce() const { return m_force; }
private:
	std::string m_id;
	float m_force;
};

class ScEngineDef
{
public:
	ScEngineDef(const std::string& id, const float force) :
	m_id(id),
	m_force(force)
	{
	}
	const std::string& getId() const { return m_id; }
	float getForce() const { return m_force; }
private:
	std::string m_id;
	float m_force;
};

class ScWheelPairAttachment
{
public:
	enum Id
	{
		eIdLeft=0,
		eIdRight
	};
	ScWheelPairAttachment(const float offset, const float axleLength, const float engineBias, const float brakeBias, const float steeringInfluence, const ScWheelDef* leftWheel, const ScSuspensionDef* leftSuspension, const ScWheelDef* rightWheel, const ScSuspensionDef* rightSuspension) :
	m_offset(offset),
	m_axleLength(axleLength),
	m_engineBias(engineBias),
	m_steeringInfluence(steeringInfluence),
	m_brakeBias(brakeBias)
	{
		m_wheels[eIdLeft]=leftWheel;
		m_suspensions[eIdLeft]=leftSuspension;
		m_wheels[eIdRight]=rightWheel;
		m_suspensions[eIdRight]=rightSuspension;
	}
	float getOffset() const { return m_offset; }
	float getAxleLength() const { return m_axleLength; }
	float getEngineBias() const { return m_engineBias; }
	float getBrakeBias() const { return m_brakeBias; }
	float getSteeringInfluence() const { return m_steeringInfluence; }
	const ScWheelDef* getWheel(const Id id) const { return m_wheels[id]; }
	const ScSuspensionDef* getSuspension(const Id id) const { return m_suspensions[id]; }
private:
	float					m_offset;
	float					m_axleLength;
	float					m_engineBias;
	float					m_steeringInfluence;
	float					m_brakeBias;
	const ScWheelDef*			m_wheels[2];
	const ScSuspensionDef*			m_suspensions[2];
};

class ScChassisDef
{
public:
	typedef std::vector<ScWheelPairAttachment*> WheelPairAttachments;

	ScChassisDef(const std::string& id, const Vector3f& halfDimensions, const float mass, const WheelPairAttachments wheelPairAttachments, const std::string& objPath) :
	m_id(id),
	m_halfDimensions(halfDimensions),
	m_mass(mass),
	m_wheelPairAttachments(wheelPairAttachments),
	m_objPath(objPath)
	{
	}
	~ScChassisDef()
	{
		for ( unsigned int i=0; i < m_wheelPairAttachments.size(); i++ )
			delete m_wheelPairAttachments[i];
	}
	const std::string& getId() const { return m_id; }
	const Vector3f& getHalfDimensions() const { return m_halfDimensions; }
	const float getMass() const { return m_mass; }
	const WheelPairAttachments& getWheelPairAttachments() const { return m_wheelPairAttachments; }
	const std::string& getObjPath() const { return m_objPath; }
private:
	std::string				m_id;
	Vector3f				m_halfDimensions;
	float					m_mass;
	WheelPairAttachments			m_wheelPairAttachments;
	std::string				m_objPath;

};

class ScCarDef
{
public:
	ScCarDef(const std::string& id, const ScEngineDef& engine, const ScBrakesDef& brakes, const ScChassisDef& chassis) :
	m_id(id),
	m_engine(engine),
	m_brakes(brakes),
	m_chassis(chassis)
	{
	}
	const std::string &getId() const { return m_id; }
	const ScEngineDef& getEngine() const { return m_engine; }
	const ScBrakesDef& getBrakes() const { return m_brakes; }
	const ScChassisDef& getChassis() const { return m_chassis; }
private:
	std::string m_id;
	const ScEngineDef& m_engine;
	const ScBrakesDef& m_brakes;
	const ScChassisDef& m_chassis;
};
class ScCarDefManager
{
private:
	friend class ScCarDefLoader;

	typedef std::map<std::string, boost::shared_ptr<ScCarDef> >		CarMap;
	typedef std::map<std::string, boost::shared_ptr<ScWheelDef> >		WheelMap;
	typedef std::map<std::string, boost::shared_ptr<ScSuspensionDef> >	SuspensionMap;
	typedef std::map<std::string, boost::shared_ptr<ScEngineDef> >		EngineMap;
	typedef std::map<std::string, boost::shared_ptr<ScBrakesDef> >		BrakesMap;
	typedef std::map<std::string, boost::shared_ptr<ScChassisDef> >		ChassisMap;

	ScWheelDef*			createWheel(const std::string& id, const float radius, const float width, const float friction, const std::string& objPath);
public: //Andy HACK
	const ScWheelDef*		getWheel(const std::string& id) const;
private:
	ScSuspensionDef*		createSuspension(const std::string& id, const float stiffness, const float damping, const float compression, const float length, const float rollInfluence, const float maximumForce);
	const ScSuspensionDef*		getSuspension(const std::string& id) const;

	ScEngineDef*			createEngine(const std::string& id, const float force);
	const ScEngineDef*		getEngine(const std::string& id) const;
	
	ScBrakesDef*			createBrakes(const std::string& id, const float force);
	const ScBrakesDef*		getBrakes(const std::string& id) const;

	ScChassisDef*			createChassis(const std::string& id, const Vector3f& halfDimensions, const float mass, const ScChassisDef::WheelPairAttachments wheelPairAttachments, const std::string& objPath);
	const ScChassisDef*		getChassis(const std::string& id) const;

	ScCarDef*			createCar(const std::string& id, const ScChassisDef& chassisDef, const ScEngineDef& engineDef, const ScBrakesDef& brakesDef);
public:
	const ScCarDef*			getCar(const std::string& id) const;
	static ScCarDefManager& instance();
private:
	WheelMap		m_wheelMap;
	SuspensionMap	m_suspensionMap;
	EngineMap		m_engineMap;
	BrakesMap		m_brakesMap;
	ChassisMap		m_chassisMap;
	CarMap			m_carMap;
};

#endif
